/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_products/zhiqim_tunneler.htm
 *
 * Zhiqim Tunneler is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.tunnel;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import org.zhiqim.kernel.util.Closes;
import org.zhiqim.kernel.util.Ids;
import org.zhiqim.kernel.util.Sockets;
import org.zhiqim.kernel.util.seqs.Sequence;

/**
 * 隧道服务端连接
 *
 * @version v1.5.0 @author zouzhigang 2018-11-2 新建与整理
 */
public class TunnelServer extends TunnelConnection
{
    private static final Sequence seq = new Sequence(4);
    
    private final Tunneler tunneler;
    private TunnelClient client;
    
    public TunnelServer(Tunneler tunneler, Socket socket, InputStream input, OutputStream output)
    {
        super("TunnelServer", Ids.longId(seq), socket, input, output);
        this.tunneler = tunneler;
    }
    
    @Override /** 线程开启前 */
    public boolean openBefore()
    {
        try
        {
            Socket socket = new Socket();
            Sockets.setOption(socket, true, 0, 0, true);
            InetSocketAddress endpoint = new InetSocketAddress(tunneler.getServerHost(), tunneler.getServerPort());
            socket.connect(endpoint, tunneler.getServerTimeout() * 1000);
            
            InputStream input = socket.getInputStream();
            OutputStream output = socket.getOutputStream();
            this.client = new TunnelClient(this, socket, input, output);
            return true;
        }
        catch(IOException e)
        {
            log.error("TunnelClient连接异常[%s]，关闭TunnelServer连接", e.getMessage());
            return false;
        }
    }
    
    @Override /** 线程关闭后 */
    public void closeAfter()
    {
        //1.关闭作为服务端的Socket
        Closes.closeIgnoreException(socket, input, output);
        
        if (client != null)
        {//2.关闭作为客户端的Socket
            client.close();
            client = null;
        }
        
        //3.从管理器中删除
        tunneler.remove(this);
    }
    
    /********************************************************************************************/
    //消息处理
    /********************************************************************************************/

    @Override /** 接收消息，转发到客户端 */
    public void receive(InputStream in) throws Exception
    {
        client.send(in);
    }
    
    @Override /** 退出 */
    public void exit()
    {
        close();
    }
    
    @Override /** 异常 */
    public void exception(Throwable e)
    {
        close();
    }
}
